import csv
import logging
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
from config import Config
import re
import downloader
import utils
from typing import Tuple, Optional
import rich_utils

"""多次尝试将csv文件中的url列表转化为pdf"""
def loop_csv_list_to_pdf(csv_path):

    csv_file_name = csv_path.stem
    pdf_out_dir = Config.OUTPUT_PDF_ROOT_DIR.joinpath(csv_file_name)
    #创建pdf文件输出目录
    pdf_out_dir.mkdir(parents=True, exist_ok=True)

    try:
        # 创建CSV读取器
        data_list, encoding = read_file_with_auto_encoding(csv_path)
        logging.debug(f"###CSV文件：读取{csv_path}，文件编码:{encoding}")

    except FileNotFoundError:
        logging.error(f"错误：文件 '{csv_path}' 不存在")
        return None
    except Exception as e:
        logging.error(f"读取CSV时出错：{str(e)}")
        return None

    progress = rich_utils.progress_x
    task_id = progress.add_task("任务生成中~~~", total=len(data_list))
    # 更新任务描述，加入task_id
    progress.update(
        task_id,
        description=f"任务{task_id}: {csv_file_name}"
    )

    max_attempts = Config.MAX_ATTEMPTS  # 最大循环次数

    for attempt in range(max_attempts):
        current_try = attempt + 1  # 转换为1-based计数（1-5次）
        logging.debug(f"第 {current_try} 次尝试...")
        try:
            csv_to_pdf(csv_path, pdf_out_dir, data_list, task_id)
            break
        except:
            logging.debug("---尝试失败，进入下次尝试---")
            if attempt == max_attempts:
                logging.error(f"已达到最大尝试次数（{max_attempts}次），读取失败，退出！！")
    logging.debug(f"###CSV文件：{csv_path}读取成功！")

def read_file_with_auto_encoding(
        file_path: Path,
        possible_encodings: Tuple[str, ...] = ("utf-8-sig", "gbk", "utf-8", "gb2312", "iso-8859-1")
) -> Tuple[Optional[list], Optional[str]]:
    """
    自动尝试多种编码读取文件，返回内容和使用的编码

    参数：
        file_path: 文件路径
        possible_encodings: 可能的编码列表（按优先级排序）

    返回：
        (文件内容, 使用的编码)：若所有编码失败，返回 (None, None)
    """
    if not file_path.exists() or not file_path.is_file():
        return None, None  # 文件不存在或不是文件

    zero_width_chars = re.compile(r'[\u200b\u200c\u200d\u200e\u200f\uFEFF]')

    for encoding in possible_encodings:
        try:
            with open(file_path, "r", encoding=encoding) as f:
                csv_reader = csv.reader(f)  # 尝试完整读取文件（触发解码）
                data_list = list(csv_reader)
                data_list[0][0] = zero_width_chars.sub('', data_list[0][0]).strip()
            return data_list, encoding  # 解码成功，返回内容和编码
        except UnicodeDecodeError:
            continue  # 解码失败，尝试下一种编码
        except Exception as e:
            logging.error(f"读取文件时发生错误（编码 {encoding}）：{str(e)}")
            continue

    # 所有编码尝试失败
    return None, None

"""将csv文件的url列表转化为pdf"""
def csv_to_pdf(file_path, out_dir, data_list, task_id):

    out_list = []
    # 创建线程池（max_workers：最大线程数，通常设为 CPU核心数 * 5 左右）
    with ThreadPoolExecutor(max_workers=Config.DATA_MAX_WORKERS, thread_name_prefix="Pool-Thread") as executor:
        # 提交任务到线程池
        futures = []
        # 等待所有任务完成，并获取结果（可选）
        for count, item in enumerate(data_list, start=1):

            # 提交任务，返回Future对象（用于获取结果）
            future = executor.submit(process_row, count, item, out_dir)
            futures.append(future)

        for future in as_completed(futures):
            result = future.result()  # 阻塞，直到该任务完成并返回结果
            out_list.append(result)
            rich_utils.progress_update(0, rich_utils.progress_x, task_id, 1)

    out_csv_path = str(Path(out_dir) / f"1.{file_path.stem}_输出结果.csv")
    with open(out_csv_path, "w", newline="") as f:
        # 创建DictWriter对象，指定表头
        writer = csv.DictWriter(f, fieldnames=["序号", "文件名", "网址", "操作", "结果"])

        # 写入表头
        writer.writeheader()
        # 写入所有行数据（每个字典对应一行）
        writer.writerows(out_list)


def process_row(row_idx: int, row_data: list, out_dir: Path) -> dict:
    """处理单行数据：判断URL类型，选择下载或转PDF"""
    try:
        if len(row_data) < 2:
            return {
                "序号": row_idx,
                "文件名": "无效数据",
                "网址": "",
                "操作": "跳过",
                "结果": "失败（数据格式错误，缺少文件名或URL）"
            }

        # 构建输出路径（用pathlib避免路径拼接错误）
        out_path = out_dir / f"{row_data[0]}.pdf"

        # 提取文件名和URL（清理空格）
        filename = re.sub(r'[\\/*?:"<>|\n\r]', '', row_data[0].strip())  # 移除文件名中的非法字符
        url = row_data[1].strip()

        if not filename or not url:
            return {
                "序号": row_idx,
                "文件名": filename or "无文件名",
                "网址": url or "无URL",
                "操作": "跳过",
                "结果": "失败（文件名或URL为空）"
            }
        # 检查是否已生成PDF（避免重复处理）
        if Path(out_path).exists():
            logging.info(f"{filename}: 已存在，跳过--")

            return {
                "序号": row_idx,
                "文件名": filename,
                "网址": url,
                "操作": "跳过",
                "结果": "成功"
            }

        # 1. 判断URL是否为可直接下载的类型
        file_suffix = utils.get_file_suffix_from_url(url)
        if file_suffix in Config.DIRECT_DOWNLOAD_SUFFIXES:
            # 直接下载：保存路径=输出目录/文件名+后缀（避免文件名重复）
            save_path = out_dir / f"{filename}{file_suffix}"
            success, msg = downloader.download_file(url, save_path)
            operation = "下载"
        else:
            # 转PDF：保存路径=输出目录/文件名.pdf
            save_path = out_dir / f"{filename}.pdf"
            success, msg = downloader.html_to_pdf(url, save_path)
            operation = "PDF转换"

        # 构建结果
        result = "成功" if success else f"失败：{msg}"
        return {
            "序号": row_idx,
            "文件名": filename,
            "网址": url,
            "操作": operation,
            "结果": result
        }

    except Exception as e:
        return {
            "序号": row_idx,
            "文件名": row_data[0] if len(row_data) > 0 else "未知",
            "网址": row_data[1] if len(row_data) > 1 else "未知",
            "操作": "异常",
            "结果": f"处理异常：{str(e)}"
        }

